Gerrit's Blog

28.12.2024

Spring Actuator Security

Show me your internals, but secured

Yesterday I was looking at this great talk about the leak of private information at Volkswagen. (Recordings will be found here https://media.ccc.de/c/38c3) Being a Java and Spring developer it made me a little bit sad that the part of the talk about the initial steps involving the Spring Boot based application sounded like all applications using the actuator are insecure by design. Yes, I can completely get that there are time constraints for such a talk and you also want to get your jokes right, and I am the last one to judge about this because I felt entertained. But let's have a more detailed look what it takes to get the heapdumps of a running Spring Boot application, how to explore them for interesting data, and -last but not least- how to secure such endpoints.

Setup

The example application does not require a huge setup. As always if I want to quickly create a Spring Boot application, I go to https://start.spring.io. The dependencies needed are the actuator and the web dependency, foremost to keep the application running.

Dependency overview at start.spring.io

After downloading and extracting the archive, the application can be started by invoking

./mvnw spring-boot:run

When accessing now the actuator endpoint of the application, the active ones are listed.

curl 'http://localhost:8080/actuator'
{
  "_links": {
    "self": {
      "href": "http://localhost:8080/actuator",
      "templated": false
    },
    "health-path": {
      "href": "http://localhost:8080/actuator/health/{*path}",
      "templated": true
    },
    "health": {
      "href": "http://localhost:8080/actuator/health",
      "templated": false
    }
  }
}

If you came here because you were afraid that every application now has a heapdump endpoint available by default, I am happy to tell you that this is not the case.

The obvious next question is: How to get the heapdump endpoint enabled?

Enabling the heapdump endpoint

A lot of properties of a Spring Boot application can be set via the application.properties configuration (or similar ways). There is not only so much built-in but also a very good documentation about all the properties being available.

Let's activate the endpoint for the heapdump explicitly. The property that needs to be set is

management.endpoints.web.exposure.include=heapdump

After restarting the application and checking back the available endpoints, this one is now activated.

{
  "_links": {
    "self": {
      "href": "http://localhost:8080/actuator",
      "templated": false
    },
    "heapdump": {
      "href": "http://localhost:8080/actuator/heapdump",
      "templated": false
    }
  }
}

As you can see, there is now only one endpoint for the heapdump and the health endpoint(s) disappeared. You might have guessed it, the property above takes a list of endpoints to activate.

Adding some credentials

To get something into the application that reflects a scenario where some sensitive data can be found, a class will be added that holds those data.

public class CloudProviderXyz {  
      
    private final String username;  
      
    private final String password;  
  
    public CloudProviderXyz(String username, String password) {  
        this.username = username;  
        this.password = password;  
    }  
}

To create an instance of this, we add a @Bean definition in the application class.

@SpringBootApplication  
public class ActuatorDemoApplication {  
      
    @Bean  
    public CloudProviderXyz cloudProviderXyz() {  
       return new CloudProviderXyz("meistermeier", "myverysecretpassword");  
    }  
  
    public static void main(String[] args) {  
       SpringApplication.run(ActuatorDemoApplication.class, args);  
    }  
  
}

After this, the application gets restarted and is ready to be inspected.

Heapdump analysis

With the actuator's heapdump endpoint enabled, it is now possible to trigger a heapdump creation and download it.

curl 'http://localhost:8080/actuator/heapdump' -O  

After downloading the file, it can be opened by any heapdump tool, e.g. VisualVm, which will be used for this example.

The overview page should look similar to this

Heapdump overview

Let's switch to the Objects view to inspect the instances alive during the time the heapdump was taken.

Objects View

Here we can search for an instance of our newly created class CloudProviderXyz. And of course with this, also its fields and their current content.

Details of CloudProviderXyz

But what could be done to avoid those data being accessible to everyone?

Bytes and obfuscation

Assuming that the credential storing class is really under our control, could the sensitive data be stored different, e.g. in an byte array to be safer? Short story short: No. Of course the byte values are readable the same way.

Byte array view

Basically this is valid for all obfuscation methods and reflects the typical security guideline: Depending on how much you make it complicated by obfuscation, the longer it will just take to reach the desired data. Even if this data is only used for a second and the enclosing object gets removed immediately, there is still the chance that the timing is right to get those sensitive data via the heapdump. It will never be 100% secure.

Externalizing the credentials

Because it is necessary to say, I assume, this won't protect the credentials within your application. But besides this, you should always externalize credentials/secrets/... using e.g. Vault or similar products. No one should ever have plain text access to those sensitive data besides the application at the time it needs it.

Securing the endpoint

As you have may already concluded, the moment your application needs some kind of secrets/credentials it will have it. If there is any need to have the feature of heapdump enabled in a production environment, it should be secured. The whole actuator feature is well documented and also mentions the needed techniques to secure the access.

Spring Security is a very mature project in the Spring ecosystem and the de-facto default when it comes to authorization and access control within Spring application. Just add its Spring Boot dependency

<dependency>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-security</artifactId>  
</dependency>

and configure a default security mechanism for all actuator endpoints.

@Bean  
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {  
    http.securityMatcher(EndpointRequest.toAnyEndpoint());  
    http.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());  
    http.httpBasic(Customizer.withDefaults());  
    return http.build();  
}

This is a simplified chain, but it can be configured to e.g. match only specific endpoints, require some group membership, or specific rights. But this would be beyond this overview.

When the application gets restarted, two things can be noted. First, there is a note about a created password:

2024-12-28T10:26:00.072+01:00  WARN 78599 --- [actuator-demo] [           main] .s.s.UserDetailsServiceAutoConfiguration : 

Using generated security password: ad882bb1-fcb3-4378-875b-1ad63c32997d

This generated password is for development use only. Your security configuration must be updated before running your application in production.

And secondly, if the heapdump endpoint gets now queried, it will deny access.

curl 'http://localhost:8080/actuator/heapdump'    
{"timestamp":"2024-12-28T09:26:06.738+00:00","status":403,"error":"Forbidden","path":"/actuator/heapdump"}

Providing the (default) username user and the generated password as HTTP basic auth parameter to the curl command

curl -u user:ad882bb1-fcb3-4378-875b-1ad63c32997d 'http://localhost:8080/actuator/heapdump'

will give us access to the endpoint. Of course as mentioned above this security setup should be hardened more and the password generator should only to be used for development.

I tried to give an overview here to put the mentioned "flaw" in Spring Boot / Actuator in some perspective and context. If there is anything, I missed, I would be happy if you ping me at https://mastodon.social/@meistermeier